﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Data;
using yq.IBase.DBHelper;

namespace yq.IBase
{
    /// <summary>
    /// 解析表达形成sql语句
    /// </summary>
    internal class WhereFunc
    {

        /// <summary>
        /// 排序
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <param name="isDesc"></param>
        /// <returns></returns>
        public static string OderBy<T>(Dictionary<Expression<Func<T, object>>, bool> dic) where T : new()
        {
            StringBuilder sb = new StringBuilder();
            foreach (var func in dic)
            {
                Expression exp = (Expression)func.Key.Body;

                if (exp is UnaryExpression)
                {
                    UnaryExpression ue = ((UnaryExpression)exp);
                    exp = ue.Operand;
                }

                if (exp is MemberExpression)
                {
                    MemberExpression me = ((MemberExpression)exp);
                    if (sb.ToString().Length==0)
                    {
                        sb.AppendFormat(me.Member.Name + (func.Value ? " desc" : ""));
                    }
                    else
                    {
                        sb.AppendFormat(","+me.Member.Name + (func.Value ? " desc" : ""));
                    }
                }
            }
            return sb.ToString().Length == 0 ? "" : " order by " + sb.ToString();
        }


        /// <summary>
        /// 排序
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <param name="isDesc"></param>
        /// <returns></returns>
        public static string OderBy<T>(Expression<Func<T, object>> func, bool isDesc = false) where T : new()
        {
            if (func != null)
            {
                Expression exp = (Expression)func.Body;
                MemberExpression me = ((MemberExpression)exp);
                if (exp != null)
                {
                    return " order by " + me.Member.Name + (isDesc ? " desc" : "");
                }
            }
            return " ";
        }



        /// <summary>
        /// 将表达式转换为sql语句
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <param name="parameter">参数集合</param>
        /// <returns></returns>
        public static string Where<T>(Expression<Func<T, bool>> func, SQLInParameter parameter = null) where T : new()
        {
            try
            {
                if (parameter == null)
                {
                    parameter = new SQLInParameter(null, null, false);
                }

                if (func.Body is BinaryExpression)
                {
                    BinaryExpression be = ((BinaryExpression)func.Body);
                    return BinarExpressionProvider(be.Left, be.Right, be.NodeType, (new T()).GetType(), parameter);
                }
                else if (func.Body is MethodCallExpression)
                {
                    MethodCallExpression be = ((MethodCallExpression)func.Body);
                    return ExpressionRouter(be, (new T()).GetType(), parameter);
                }
                else
                    return " 1=1";
            }
            catch (Exception e)
            {
                object d = e;
            }
            return " 1=1";
        }

        private static string BinarExpressionProvider(Expression left, Expression right, ExpressionType type, Type modeltype, SQLInParameter parameter)
        {
            string sb = "(";
            //先处理左边
            sb += ExpressionRouter(left, modeltype, parameter);

            sb += ExpressionTypeCast(type);

            //再处理右边
            string tmpStr = ExpressionRouter(right, modeltype, parameter);
            if (tmpStr == "null")
            {
                if (sb.EndsWith(" ="))
                    sb = sb.Substring(0, sb.Length - 2) + " is null";
                else if (sb.EndsWith("<>"))
                    sb = sb.Substring(0, sb.Length - 2) + " is not null";
            }
            else
                sb += tmpStr;
            return sb += ")";
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="exp"></param>
        /// <param name="modeltype"></param>
        /// <param name="parameter"></param>
        /// <param name="methodName">链接方式 比如like</param>
        /// <returns></returns>
        private static string ExpressionRouter(Expression exp, Type modeltype, SQLInParameter parameter, string methodName = "")
        {
            string sb = string.Empty;
            if (exp is BinaryExpression)
            {
                BinaryExpression be = ((BinaryExpression)exp);
                return BinarExpressionProvider(be.Left, be.Right, be.NodeType, modeltype, parameter);
            }
            else if (exp is MemberExpression)
            {
                MemberExpression me = ((MemberExpression)exp);

                //me.Expression.Type.FullName == modeltype.FullName&&
                if (me.Expression != null && me.Expression.NodeType == ExpressionType.Parameter)
                {
                    return me.Member.Name;
                }
                else
                {
                    var value = Expression.Lambda(me).Compile().DynamicInvoke();

                    //处理Enum
                    if (me.Type.BaseType.Name == "Enum")
                    {
                        return parameter.Set(value.GetHashCode(), me.Type, methodName);
                    }

                    return parameter.Set(value, me.Type, methodName);
                }
            }
            else if (exp is NewArrayExpression)
            {
                NewArrayExpression ae = ((NewArrayExpression)exp);
                StringBuilder tmpstr = new StringBuilder();
                foreach (Expression ex in ae.Expressions)
                {
                    tmpstr.Append(ExpressionRouter(ex, modeltype, parameter));
                    tmpstr.Append(",");
                }
                return tmpstr.ToString(0, tmpstr.Length - 1);
            }
            else if (exp is MethodCallExpression)
            {
                MethodCallExpression mce = (MethodCallExpression)exp;
                if (mce.Method.Name == "Like")
                {

                    string parameterTxt = ExpressionRouter(mce.Arguments[1], modeltype, parameter, mce.Method.Name);


                    return string.Format("({0} like {1})", ExpressionRouter(mce.Arguments[0], modeltype, parameter), parameterTxt);
                }

                    //  else if (mce.Method.Name == "NotLike")
                //     return string.Format("({0} Not like {1})", ExpressionRouter(mce.Arguments[0], modeltype, parameter), ExpressionRouter(mce.Arguments[1], modeltype, parameter));
                else if (mce.Method.Name == "In")
                    return string.Format("{0} In ({1})", ExpressionRouter(mce.Arguments[0], modeltype, parameter), ExpressionRouter(mce.Arguments[1], modeltype, parameter));
                else if (mce.Method.Name == "NotIn")
                    return string.Format("{0} Not In ({1})", ExpressionRouter(mce.Arguments[0], modeltype, parameter), ExpressionRouter(mce.Arguments[1], modeltype, parameter));
                else
                {
                    object obj = Expression.Lambda(exp).Compile().DynamicInvoke();
                    return parameter.Set(obj, exp.Type, "");
                }
            }
            else if (exp is ConstantExpression)
            {
                ConstantExpression ce = ((ConstantExpression)exp);
                if (ce.Value == null)
                    return "null";
                else
                    return parameter.Set(ce.Value, ce.Type, "");
            }
            else if (exp is UnaryExpression)
            {
                UnaryExpression ue = ((UnaryExpression)exp);
                return ExpressionRouter(ue.Operand, modeltype, parameter);
            }

            return null;
        }

        static string ExpressionTypeCast(ExpressionType type)
        {
            switch (type)
            {
                case ExpressionType.And:
                case ExpressionType.AndAlso:
                    return " AND ";
                case ExpressionType.Equal:
                    return " =";
                case ExpressionType.GreaterThan:
                    return " >";
                case ExpressionType.GreaterThanOrEqual:
                    return ">=";
                case ExpressionType.LessThan:
                    return "<";
                case ExpressionType.LessThanOrEqual:
                    return "<=";
                case ExpressionType.NotEqual:
                    return "<>";
                case ExpressionType.Or:
                case ExpressionType.OrElse:
                    return " Or ";
                case ExpressionType.Add:
                case ExpressionType.AddChecked:
                    return "+";
                case ExpressionType.Subtract:
                case ExpressionType.SubtractChecked:
                    return "-";
                case ExpressionType.Divide:
                    return "/";
                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked:
                    return "*";
                default:
                    return null;
            }
        }
    }

    /// <summary>
    /// sql参数
    /// </summary>
    internal class SQLInParameter
    {
        DbHelper cn;

        //是否使用AddInParameter形式
        bool isOpen;

        int index = 0;

        System.Data.Common.DbCommand comm;

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="_cn"></param>
        /// <param name="_comm"></param>
        /// <param name="_isOpen">是否使用参数形式</param>
        public SQLInParameter(DbHelper _cn, System.Data.Common.DbCommand _comm, bool _isOpen = true)
        {
            cn = _cn;
            isOpen = _isOpen;
            comm = _comm;
        }


        public string Set(dynamic value)
        {
            return Set(value, value.GetType(), "");
        }

        /// <summary>
        /// 添加参数
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public string Set(object value, Type valueType, string methodName)
        {
            //if (methodName == "Like")
            //{
            //    value = "%" + value + "%";
            //}

            if (isOpen)
            {
                string key = "@pm" + index++;

                DbType type = GetDbType(valueType);

                cn.AddInParameter(comm, key, type, value);

                return key;
            }
            else
            {
                if (value is string || value is DateTime || value is char)
                {
                    return string.Format("'{0}'", ExtFilter(value.ToString()));
                }
                else
                {
                    return value.ToString();
                }
            }
        }

        /// <summary>
        /// 获取类型对应DbType中的具体枚举
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static System.Data.DbType GetDbType(Type type)
        {
            String name = type.Name;

            DbType val = DbType.String;
            try
            {
                val = (DbType)Enum.Parse(typeof(DbType), name, true);

            }
            catch (Exception)
            {

            }

            return val;
        }

        /// <summary>
        /// 过滤非法字符
        /// </summary>
        /// <param name="str">要处理的字符</param>
        /// <returns>string</returns>
        private  string ExtFilter(string str)
        {
            if (!string.IsNullOrEmpty(str))
            {
                str = str.ToLower();
                str = str.Replace("<", " >");//处理小于号   
                str = str.Replace(">", "< ");//处理大于号  
                str = str.Replace("&", "");
                str = str.Replace("%20", "");
                str = str.Replace("--", "");
                str = str.Replace("==", "");
            }
            return str;
        }

    }
}
